package jp.sourceforge.akjrcp.dropsomething;

import com.akjava.lib.standards.process.ProcessPrinter;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;

import jp.sourceforge.akjrcp.util.StatusBarUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class DropsomethingTab extends Composite implements FilenameFilter{
	public static Log log = LogFactory.getLog(DropsomethingTab.class);
	private ProgressAndList plist;
	private StackLayout stack;
	private Composite controler;
	
	private boolean canConvert;
	private boolean cancel;
	
	private String preferenceKey;
	
	/**@deprecated
	 * 
	 */
	protected int progressMaxBytes;
	protected long progressMaxTime;
	
	protected long startTime;
	protected long progressTime;
	protected int progressKBytes;
	
	private ProcessPrinter processPrinter;
	
	private String cantConvertMessage=Messages.getString("dropsomething.err_initialized");
	
	public String getPreferenceKey() {
		return preferenceKey;
	}
	private ViewPart viewPart;
	
	public void setPreferenceKey(String preferenceKey) {
		this.preferenceKey = preferenceKey;
	}
	public DropsomethingTab(Composite parent, int style) {
		this(parent,style,null);
	}
	
	public DropsomethingTab(Composite parent, int style,String preferenceKey) {
		super(parent, style);
		setPreferenceKey(preferenceKey);
		// TODO Auto-generated constructor stub
		stack = new StackLayout();
		this.setLayout(stack);
		
		plist = new ProgressAndList(this, SWT.NONE);
		plist.getSimpleFileList().setInput(new ArrayList());//is that work?
		plist.getCancelButton().addSelectionListener(new CancelAction());
		
		plist.setFilenameFilter(this);
		controler = createControls(this);
		stack.topControl=controler;
		
		new DropMonitor(controler);
	}
	
	
	public void progressBytes(int kByte){
		if(kByte==0||progressMaxBytes==0){
			return;
		}
		int p=kByte*100/progressMaxBytes;
		setProgress(p);
	}
	
	public void progressTime(long time){
		if(time==0||progressMaxTime==0){
			return;
		}
		int p=(int) (time*100/progressMaxTime);
		setProgress(p);
	}
	
	public void setProgress(int persent){
		PlatformUI.getWorkbench().getDisplay().syncExec(new SetProgress(persent));//sync is better work.
	}
	
	public class SetProgress implements Runnable{
		private int value;
		public SetProgress(int value){
			this.value=value;
		}
		public void run() {
			plist.getProgressBar().setSelection(value);
		}
		
	}
	public void setCenterText(String text){
		PlatformUI.getWorkbench().getDisplay().syncExec(new SetCenterText(text));//sync is better work.
	}
	public class SetCenterText implements Runnable{
		private String infoText;
		public SetCenterText(String infoText){
			this.infoText=infoText;
		}
		public void run() {
			plist.setCenterLabelText(infoText);
		}
		
	}
	
	public void setHeaderText(String text){
		PlatformUI.getWorkbench().getDisplay().syncExec(new SetHeaderText(text));//sync is better work.
	}
	public class SetHeaderText implements Runnable{
		private String infoText;
		public SetHeaderText(String infoText){
			this.infoText=infoText;
		}
		public void run() {
			plist.setHeaderLabelText(infoText);
		}
		
	}
	/**
	 * cancel exectuing.
	 * call cancelConvert methods
	 * annd back to normal mode.
	 *should use perfomeCancel()
	 */
	protected void actionCancel(){
		cancel=true;
		cancelConvert();//kill process
		plist.getSimpleFileList().removeFiles();
		
		
		
		releaseConvert();//for remove dialog
		//redraw;
		stack.topControl = controler;
		layout();
		redraw();
	}

	public class CancelAction implements SelectionListener{

		public void widgetSelected(SelectionEvent e) {
			actionCancel();
		}

		public void widgetDefaultSelected(SelectionEvent e) {
			
		}
		
	}
	public abstract Composite createControls(Composite parent);
	
	/*
	 * called from drag and drop
	 */
	public  void startConvert(){
		cancel=false;
		plist.getSimpleFileList().getTable().select(0);
		
		initConvert();
		beforeConvert();
		
		Thread t = new Thread(new ConvertFile());
		t.start();
	}

	
	public class ConvertFile implements Runnable {
		public void run() {
			while (true) {
				int size = plist.getSimpleFileList().countFiles();
				if (size == 0 || cancel) { //call cancel when finished.
					PlatformUI.getWorkbench().getDisplay().syncExec( //changed to syncExec
							new FinishConvert());
					break;
				}
				
				File file = plist.getSimpleFileList().getFileList()[0];
				try {
					inconvert(file);
				} catch (DropSomethingException e) {
					StatusBarUtils.showStatusBar(e.getStatusMessage());
					if(processPrinter!=null){
						try {
							processPrinter.printError(e.getLogMessage());
						} catch (IOException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					}
					perfomeCancel();//TODO stop only each file
					e.printStackTrace();
				}
				
				// change xxx.
				plist.getSimpleFileList().popFile();

				//for show list.
				PlatformUI.getWorkbench().getDisplay().syncExec( //changed to syncExec
						new UpdateTable());
			}
		}
		
	}

	protected void perfomeCancel(){
		PlatformUI.getWorkbench().getDisplay().syncExec(new ActionCancel());
	}
	protected class ActionCancel extends Thread{
		public void run(){
			actionCancel();
		}
	}
	/**
	 * abstract method main File execute
	 *
	 */
	public abstract void inconvert(File file) throws DropSomethingException;
	/**
	 * abstract method for initialize setting
	 *
	 */
	public abstract void beforeConvert();
	public abstract void afterConvert();
	public abstract void cancelConvert();

	public class FinishConvert implements Runnable {
		public void run() {
			log.info("finish converting");
			afterConvert();
			releaseConvert();
			stack.topControl = controler;
			layout();
			redraw();
		}
	}

	public class UpdateTable implements Runnable {
		public void run() {
			
			plist.getSimpleFileList().refresh(true);
			if(plist.getSimpleFileList().countFiles()>0){
				plist.getSimpleFileList().getTable().select(0);
			}
			
		}
	}
	
	public class DropMonitor extends DropTargetAdapter {
		public DropMonitor(Composite controler){
			Transfer[] types = new Transfer[] { FileTransfer.getInstance() };

			int operations = DND.DROP_MOVE | DND.DROP_COPY;

			DropTarget target2 = new DropTarget(controler, operations);
			target2.setTransfer(types);

			target2.addDropListener(this);
		}
		public void dragEnter(DropTargetEvent event) {
			// log.infodrag enter:"+event.data);
		}

		public void dragOver(DropTargetEvent event) {
			// log.infodrag over:"+event.data);
		}

		public void drop(DropTargetEvent event) {
			//log.info("cancovert:"+isCanConvert());
					
			if(isCanConvert()){
			

			// log.info(event.data.getClass().getName());
			String files[] = (String[]) event.data;

			for (int i = 0; i < files.length; i++) {
				addDragAndDropFile(files[i]);
			}

			}else{
				log.info("cant convert:"+cantConvertMessage);
				StatusBarUtils.showStatusBar(cantConvertMessage);
			}
		}
	}

	public void addDragAndDropFile(String path) {
		if (stack.topControl == controler) {
			stack.topControl = plist;
			plist.addFile(path);
			
			layout();

			// little bit worry
			startConvert();

		} else {
			plist.addFile(path);
			layout();
		}

	}

	public boolean isCanConvert() {
		return canConvert;
	}

	public void setCanConvert(boolean canConvert) {
		
		this.canConvert = canConvert;
	}
	
	public int compare(Object object){
		if(object instanceof DropsomethingTab){
			//
		}
		return -1;
	}
	
	//for extends the class
	/**
	 * this method called beforeConvert
	 */
	public void initConvert(){
		
	}
	
	public void releaseConvert(){
		
	}

	//default path all file
	public boolean accept(File parent,String name){
		return true;
	}
	/**@deprecated
	 * 
	 * 
	 */
	public int getProgressMaxBytes() {
		return progressMaxBytes;
	}
	/**@deprecated
	 * 
	 * @param progressMaxBytes
	 */
	public void setProgressMaxBytes(int progressMaxBytes) {
		this.progressMaxBytes = progressMaxBytes;
	}
	public ViewPart getViewPart() {
		return viewPart;
	}
	public void setViewPart(ViewPart viewPart) {
		this.viewPart = viewPart;
	}
	

	public class DropSomethingException extends Exception{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private String logMessage;
		private String statusMessage;
		public DropSomethingException(String messages,String statusMessage,String logMessage){
			super(messages);
			this.statusMessage=statusMessage;
			this.logMessage=logMessage;
		}
		public String getLogMessage() {
			return logMessage;
		}
		public void setLogMessage(String logMessage) {
			this.logMessage = logMessage;
		}
		public String getStatusMessage() {
			return statusMessage;
		}
		public void setStatusMessage(String statusMessage) {
			this.statusMessage = statusMessage;
		}
	}


	public ProcessPrinter getProcessPrinter() {
		return processPrinter;
	}
	public void setProcessPrinter(ProcessPrinter processPrinter) {
		this.processPrinter = processPrinter;
	}
	public String getCantConvertStatusbarMessage() {
		return cantConvertMessage;
	}
	public void setCantConvertStatusbarMessage(String cantConvertMessage) {
		this.cantConvertMessage = cantConvertMessage;
	}
	public long getProgressMaxTime() {
		return progressMaxTime;
	}
	public void setProgressMaxTime(long progressMaxTime) {
		this.progressMaxTime = progressMaxTime;
	}
	public void setProgressKBytes(int kbytes) {
		this.progressKBytes=kbytes;
	}
	public long getProgressTime() {
		return progressTime;
	}
	public void setProgressTime(long progressTime) {
		this.progressTime = progressTime;
	}
	public long getStartTime() {
		return startTime;
	}
	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}
	public int getProgressKBytes() {
		return progressKBytes;
	}

	
}
